#include <iomanip>
#include <sstream>
#include <utility>

#include "PauseScreen.h"
#include "Scene.h"
#include "FontManager.h"
#include "glslshader.h"
#include "geom.h"
#include "Button.h"
#include "FreeTypeFont.h"

using namespace std;

GLuint PauseScreen::m_vertexBuffer = 0;
GLuint PauseScreen::m_colorBuffer = 0;
GLSLProgram* PauseScreen::m_shaderProgram = NULL;

PauseScreen::PauseScreen(void)
    : m_resumeBtn(NULL), m_mainMenuBtn(NULL), m_exitBtn(NULL)
{
}

PauseScreen::PauseScreen(boost::shared_ptr<Scene> scene)
    : m_scene(scene), m_resumeBtn(NULL), m_mainMenuBtn(NULL), m_exitBtn(NULL)
{
}

PauseScreen::~PauseScreen(void)
{
}

bool PauseScreen::initialize(void)
{
    //Viewport[2] stores the width of the viewport, vieport[3] stores the height
    //We pass these into our font so the ortho mode can set the resolution for the window
    GLint viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport);

    FontManager* fontManager = FontManager::getInstance();
    if (fontManager->hasFont(make_pair("data/textures/ANGRY_BIRDS.ttf", 48)))
    {
        m_font = fontManager->getFont(make_pair("data/textures/ANGRY_BIRDS.ttf", 48));
    }
    else
    {
        m_font = boost::shared_ptr<FreeTypeFont>(new FreeTypeFont("data/textures/ANGRY_BIRDS.ttf",
                              viewport[2], 
                              viewport[3], 
                              48));
        fontManager->addFont(m_font);
    }

    if (!initBackground())
    {
        return false;
    }

    m_resumeBtn = new Button(m_scene);
    m_resumeBtn->setDimension(Dimension(148.0f, 42.0f));
    m_resumeBtn->setPosition(Vector3(viewport[2]/2.0f, 300.0f, 0.0f));
    if (!m_resumeBtn->initialize()) {
        std::cerr << "Could not initialize the Resume Button" << std::endl;
        return false;
    }
    m_resumeBtn->setFontSize(24);
    m_resumeBtn->setLabel("RESUME ");

    m_mainMenuBtn = new Button(m_scene);
    m_mainMenuBtn->setDimension(Dimension(148.0f, 42.0f));
    m_mainMenuBtn->setPosition(Vector3(viewport[2]/2.0f, 250.0f, 0.0f));
    if (!m_mainMenuBtn->initialize()) {
        std::cerr << "Could not initialize the MainMenu Button" << std::endl;
        return false;
    }
    m_mainMenuBtn->setFontSize(24);
    m_mainMenuBtn->setLabel("MAIN MENU");

    m_exitBtn = new Button(m_scene);
    m_exitBtn->setDimension(Dimension(148.0f, 42.0f));
    m_exitBtn->setPosition(Vector3(viewport[2]/2.0f, 200.0f, 0.0f));
    if (!m_exitBtn->initialize()) {
        std::cerr << "Could not initialize the Exit Button" << std::endl;
        return false;
    }
    m_exitBtn->setFontSize(24);
    m_exitBtn->setLabel("EXIT ");

    //Return success
    return true;
}

void PauseScreen::prepare(float dt)
{
    // Update buttons
    m_resumeBtn->prepare(dt);
    m_mainMenuBtn->prepare(dt);
    m_exitBtn->prepare(dt);
}

void PauseScreen::render(void)
{
    renderBackground();

    Dimension screenSize = m_scene->getScreenSize();
    m_font->printString("PAUSE", 
                        (screenSize.width / 2.0f) - 70.0f, 
                        (screenSize.height / 2.0f) + 60.0f);

    // Render buttons
    m_resumeBtn->render();
    m_mainMenuBtn->render();
    m_exitBtn->render();
}

bool PauseScreen::resumeButtonPressed(void) const
{
    return m_resumeBtn->isClicked();
}

bool PauseScreen::mainButtonPressed(void) const
{
    return m_mainMenuBtn->isClicked();
}

bool PauseScreen::exitButtonPressed(void) const
{
    return m_exitBtn->isClicked();
}

void PauseScreen::resetResumeButton(void)
{
    m_resumeBtn->setClicked(false);
}

void PauseScreen::resetMainButton(void)
{
    m_mainMenuBtn->setClicked(false);
}

void PauseScreen::resetExitButton(void)
{
    m_exitBtn->setClicked(false);
}

bool PauseScreen::initBackground(void)
{
    Dimension screenSize = m_scene->getScreenSize();
    GLfloat vertex [] = { 0.0f, 0.0f, //First Square vertex
        static_cast<GLfloat>(screenSize.width), 0.0f,
        static_cast<GLfloat>(screenSize.width), static_cast<GLfloat>(screenSize.height),
        0.0f, static_cast<GLfloat>(screenSize.height)  //Last Square vertex
    };

    glGenBuffers(1, &m_vertexBuffer); //Generate a buffer for the vertices
    glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); //Bind the vertex buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, &vertex[0], GL_STATIC_DRAW); //Send the data to OpenGL

    GLfloat color [] = { 0.75f, 0.75f, 0.75f, 0.6f,
                         0.75f, 0.75f, 0.75f, 0.6f,
                         0.75f, 0.75f, 0.75f, 0.6f,
                         0.75f, 0.75f, 0.75f, 0.6f
                       };

    glGenBuffers(1, &m_colorBuffer); //Generate a buffer for the colors
    glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer); //Bind the color buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 16, &color[0], GL_STATIC_DRAW); //Send the data to OpenGL

    m_shaderProgram = new GLSLProgram("data/shaders/basic-RGBAcolor.vert", 
                                      "data/shaders/basic-RGBAcolor.frag");

    if (!m_shaderProgram->initialize())
    {
        std::cerr << "Could not initialize the Pause Screen shaders" << std::endl;
        return false;
    }

    m_shaderProgram->bindAttrib(0, "a_Vertex");
    m_shaderProgram->bindAttrib(1, "a_Color");
    m_shaderProgram->linkProgram();

    return true;
}

void PauseScreen::renderBackground(void) const
{
    static float modelviewMatrix[16];
    static float projectionMatrix[16];

    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glPushMatrix();
    glTranslatef(0.0f, 0.0f, 0.0f); 

    glGetFloatv(GL_MODELVIEW_MATRIX, modelviewMatrix);
    glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix);

    m_shaderProgram->bindShader();
    m_shaderProgram->sendUniform4x4("modelview_matrix", modelviewMatrix);
    m_shaderProgram->sendUniform4x4("projection_matrix", projectionMatrix);

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
    glVertexAttribPointer((GLint)0, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer);
    glVertexAttribPointer((GLint)1, 4, GL_FLOAT, GL_FALSE, 0, 0);

    glDrawArrays(GL_QUADS, 0, 4);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);

    glPopMatrix();

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glDisable(GL_BLEND);

}
